﻿#include <Windows.h>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <vtkfmt/format.h>
#include <vtkfmt/args.h>
#include <xiosbase>

#include "Geometry.h"
#include "Mesh.h"
#include "Project.h"
#include "easyloggingpp.h"
#include "MeshDictFormater.h"

#include "catalyst.hpp"
#include "BoundingBoxNodeName.h"

INITIALIZE_EASYLOGGINGPP
namespace fs = std::filesystem;
const char* systemSubWorkspace = "\\system";
const char* initializeSubWorkspace = "\\0";
const char* initializeIncludeSubWorkspace = "\\include";
const char* constantSubWorkspace = "\\constant";
Project::Project()
  : m_WorkSpace("")
  , m_SystemSubSpace("")
  , m_Geometry(nullptr)
  , m_Mesh(nullptr)
{

}

Project::~Project() 
{

}

void Project::CreateWorkSpace(const std::string& workspace)
{
  LOG(INFO) << "work space: " << workspace;

  if (workspace.empty())
  {
    LOG(ERROR) << "workspace is empty!";
    return;
  }

  //create workspace
  m_WorkSpace = workspace;
  fs::create_directories(fs::path(m_WorkSpace));

  //create sub workspace
  CreateSubWorkSpace_i();
}

void Project::CreateSubWorkSpace_i()
{
  // create system sub workspace
  m_SystemSubSpace = m_WorkSpace + systemSubWorkspace;
  m_InitializeSubSpace = m_WorkSpace + initializeSubWorkspace;
  m_ConstantSubSpace = m_WorkSpace + constantSubWorkspace;
  m_initializeIncludeSubWorkspace = m_WorkSpace + initializeSubWorkspace + initializeIncludeSubWorkspace;
  fs::create_directories(fs::path(this->m_SystemSubSpace));
  fs::create_directories(fs::path(this->m_InitializeSubSpace));
  fs::create_directories(fs::path(this->m_ConstantSubSpace));
  fs::create_directories(fs::path(this->m_initializeIncludeSubWorkspace));
}

void Project::CopyGeometryToTarget_i()
{
  fs::path sourceGeometryPath = m_Geometry->GetSourcePath();
  fs::path targetSpace = m_WorkSpace;
  auto targetGeometryPath = targetSpace / m_Geometry->GetFileName();
  m_Geometry->SetTargetPath(targetGeometryPath.string());
  try
  {
    fs::copy_file(sourceGeometryPath, targetGeometryPath, fs::copy_options::overwrite_existing);
  }
  catch (const std::exception& e)
  {
    LOG(ERROR) << e.what();
  }
}

//void Project::EditGeometrySolid_i()
//{
//  std::ofstream outFile;
//  outFile.open(m_Geometry->GetTargetPath());
//  std::string findword;
//  std::ifstream MyReadFile(m_Geometry->GetSourcePath());
//  int solidLine = 1;
//  while (std::getline(MyReadFile, findword))
//  {
//    if (findword.find("solid") != -1)
//    {
//      if (solidLine == 1)
//      {
//        findword = "solid " + m_Geometry->GetStem();
//      }
//      else
//      {
//        findword = "endsolid " + this->m_Geometry->GetStem();
//      }
//      solidLine++;
//    }
//    // Output the newstl from the file
//    outFile << findword << std::endl;
//  }
//  //std::cout << "TotalLineNumber = " << solidLine << std::endl;
//  // Close the file
//  MyReadFile.close();
//  // done with file
//  outFile.close();
//}

void Project::UpdateaIncludeInitialConditions_i()
{
  std::string initialConditions_dict = R"(
/*--------------------------------*- C++ -*----------------------------------*\
| =========                 |                                                 |
| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
|  \\    /   O peration     | Version:  v1806                                 |
|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
|    \\/     M anipulation  |                                                 |
\*---------------------------------------------------------------------------*/

flowVelocity         (40 0 0);
pressure             0;
turbulentKE          3.375;
turbulentOmega       180;
rho		     1.2;

// ************************************************************************* //
)";

  std::ofstream initialConditions_dict_file(this->m_initializeIncludeSubWorkspace + "/initialConditions");
  initialConditions_dict_file << initialConditions_dict;
}
void Project::UpdateaIncludeFixedInlet_i()
{
  std::string fixedInlet_dict = R"(
/*--------------------------------*- C++ -*----------------------------------*\
| =========                 |                                                 |
| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
|  \\    /   O peration     | Version:  v1806                                 |
|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
|    \\/     M anipulation  |                                                 |
\*---------------------------------------------------------------------------*/

inlet
{
    type  fixedValue;
    value $internalField;
}

// ************************************************************************* //
)";

  std::ofstream fixedInlet_dict_file(this->m_initializeIncludeSubWorkspace + "/fixedInlet");
  fixedInlet_dict_file << fixedInlet_dict;
}
void Project::UpdateaIncludefrontBackUpperPatches_i()
{
  std::string frontBackUpperPatches_dict = R"(
/*--------------------------------*- C++ -*----------------------------------*\
| =========                 |                                                 |
| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
|  \\    /   O peration     | Version:  v1806                                 |
|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
|    \\/     M anipulation  |                                                 |
\*---------------------------------------------------------------------------*/

side_wall
{
    type slip;
}

// ************************************************************************* //
)";

  std::ofstream frontBackUpperPatches_dict_file(this->m_initializeIncludeSubWorkspace +"/frontBackUpperPatches");
  frontBackUpperPatches_dict_file << frontBackUpperPatches_dict;
}


void Project::UpdateaPressure_i()
{
  std::string pressure_dict = R"(
/*--------------------------------*- C++ -*----------------------------------*\
| =========                 |                                                 |
| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
|  \\    /   O peration     | Version:  5                                     |
|   \\  /    A nd           | Web:      www.OpenFOAM.org                      |
|    \\/     M anipulation  |                                                 |
\*---------------------------------------------------------------------------*/
FoamFile
{
    version     2.0;
    format      ascii;
    class       volScalarField;
    object      p;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

dimensions      [0 2 -2 0 0 0 0];

internalField   uniform 0;

boundaryField
{
    inlet
    {
        type            zeroGradient;
    }

    outlet
    {
        type            fixedValue;
        value           $internalField;
    }
    
    cylinder
    {
        type            zeroGradient;
    }

    side
    {
        type            symmetry;
    }
}

// ************************************************************************* //
)";

  std::ofstream pressure_dict_file(this->m_InitializeSubSpace + "/p");
  pressure_dict_file << pressure_dict;
}
void Project::UpdateaVelocity_i()
{
  std::string velocity_dict = R"(
/*--------------------------------*- C++ -*----------------------------------*\
| =========                 |                                                 |
| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
|  \\    /   O peration     | Version:  5                                     |
|   \\  /    A nd           | Web:      www.OpenFOAM.org                      |
|    \\/     M anipulation  |                                                 |
\*---------------------------------------------------------------------------*/
FoamFile
{
    version     2.0;
    format      ascii;
    class       volVectorField;
    object      U;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

Uinlet          (0.015 0 0);

dimensions      [0 1 -1 0 0 0 0];

internalField   uniform (0 0 0);

boundaryField
{

    inlet
    {
        type            fixedValue;
        value           uniform $Uinlet;
    }
    
    outlet
    {
        type            zeroGradient;
    }
    cylinder
    {
        type            noSlip;
    }
    side
    {
        type            symmetry;
    }
}


// ************************************************************************* //
)";

  std::ofstream velocity_dict_file(this->m_InitializeSubSpace + "/U");
  velocity_dict_file << velocity_dict;
}
void Project::UpdateaOmega_i()
{
  std::string omega_dict = R"(
/*--------------------------------*- C++ -*----------------------------------*\
| =========                 |                                                 |
| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
|  \\    /   O peration     | Version:  v1806                                 |
|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
|    \\/     M anipulation  |                                                 |
\*---------------------------------------------------------------------------*/
FoamFile
{
    version     2.0;
    format      ascii;
    class       volScalarField;
    object      omega;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

#include        "include/initialConditions"

dimensions      [0 0 -1 0 0 0 0];

internalField   uniform $turbulentOmega;

boundaryField
{
    #includeEtc "caseDicts/setConstraintTypes"

    #include "include/fixedInlet"

    outlet
    {
        type            inletOutlet;
        inletValue      $internalField;
        value           $internalField;
    }

    ground
    {
        type            omegaWallFunction;
        value           $internalField;
    }

    car
    {
        type            omegaWallFunction;
        value           $internalField;
    }

    #include "include/frontBackUpperPatches"
}


// ************************************************************************* //

)";

  std::ofstream omega_dict_file(this->m_InitializeSubSpace + "/omega");
  omega_dict_file << omega_dict;
}
void Project::UpdateaKinetic_i()
{
  std::string kinetic_dict = R"(
/*--------------------------------*- C++ -*----------------------------------*\
| =========                 |                                                 |
| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
|  \\    /   O peration     | Version:  5                                     |
|   \\  /    A nd           | Web:      www.OpenFOAM.org                      |
|    \\/     M anipulation  |                                                 |
\*---------------------------------------------------------------------------*/
FoamFile
{
    version     2.0;
    format      ascii;
    class       volScalarField;
    object      k;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

dimensions      [0 2 -2 0 0 0 0];

internalField   uniform 0.1;

boundaryField
{
    inlet
    {
        type            turbulentIntensityKineticEnergyInlet;
        intensity       0.25;
        value           uniform 0.25;
    }
    
    outlet
    {
        type            zeroGradient;
    } 
      
    cylinder
    {
        type            kqRWallFunction;
        value           1;
    }
    
    side
    {
        type            symmetry;
    }

}
// ************************************************************************* //
)";

  std::ofstream kinetic_dict_file(this->m_InitializeSubSpace + "/k");
  kinetic_dict_file << kinetic_dict;
}
void Project::UpdateaEpsilon_i()
{
  std::string epsilon_dict = R"(
/*--------------------------------*- C++ -*----------------------------------*\
| =========                 |                                                 |
| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
|  \\    /   O peration     | Version:  5                                     |
|   \\  /    A nd           | Web:      www.OpenFOAM.org                      |
|    \\/     M anipulation  |                                                 |
\*---------------------------------------------------------------------------*/
FoamFile
{
    version     2.0;
    format      ascii;
    class       volScalarField;
    object      epsilon;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

epsilonInlet  1;

dimensions      [0 2 -3 0 0 0 0];

internalField   uniform $epsilonInlet;

boundaryField
{
    inlet
    {
        type            fixedValue;
        value           uniform $epsilonInlet;
    }

    outlet
    {
        type            zeroGradient;
    }

    cylinder
    {
        type            epsilonWallFunction;
        value           uniform $epsilonInlet;
    }
      
    side
    {
        type            symmetry;
    }
}

// ************************************************************************* //
)";

  std::ofstream epsilon_dict_file(this->m_InitializeSubSpace + "/epsilon");
  epsilon_dict_file << epsilon_dict;
}
void Project::UpdateaNut_i()
{
  std::string nut_dict = R"(
/*--------------------------------*- C++ -*----------------------------------*\
| =========                 |                                                 |
| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
|  \\    /   O peration     | Version:  5                                     |
|   \\  /    A nd           | Web:      www.OpenFOAM.org                      |
|    \\/     M anipulation  |                                                 |
\*---------------------------------------------------------------------------*/
FoamFile
{
    version     2.0;
    format      ascii;
    class       volScalarField;
    object      nut;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

dimensions      [0 2 -1 0 0 0 0];

internalField   uniform 0.01934;

boundaryField
{
    inlet
    {
        type            calculated;
        value           uniform 0.01934;
    }

    outlet
    {
        type            calculated;
        value           uniform 0;
    }
    cylinder
    {
        type            nutkWallFunction;
        value           uniform 0;
    }
    side
    {
        type            symmetry;
    }
}


// ************************************************************************* //

)";

  std::ofstream nut_dict_file(this->m_InitializeSubSpace + "/nut");
  nut_dict_file << nut_dict;
}

void Project::UpdateaTransportProperties_i()
{
  std::string transportProperties_dict = R"(
/*--------------------------------*- C++ -*----------------------------------*\
| =========                 |                                                 |
| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
|  \\    /   O peration     | Version:  v1806                                 |
|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
|    \\/     M anipulation  |                                                 |
\*---------------------------------------------------------------------------*/
FoamFile
{
    version     2.0;
    format      ascii;
    class       dictionary;
    object      transportProperties;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

transportModel  Newtonian;

nu              1.5e-05;

// ************************************************************************* //

)";

  std::ofstream transportProperties_dict_file(this->m_ConstantSubSpace + "/transportProperties");
  transportProperties_dict_file << transportProperties_dict;
}
void Project::UpdateaTurbulenceProperties_i()
{
  std::string turbulenceProperties_dict = R"(
/*--------------------------------*- C++ -*----------------------------------*\
| =========                 |                                                 |
| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
|  \\    /   O peration     | Version:  v1806                                 |
|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
|    \\/     M anipulation  |                                                 |
\*---------------------------------------------------------------------------*/
FoamFile
{
    version     2.0;
    format      ascii;
    class       dictionary;
    object      transportProperties;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

transportModel  Newtonian;

nu              1.5e-05;

// ************************************************************************* //

)";

  std::ofstream turbulenceProperties_dict_file(this->m_ConstantSubSpace + "/turbulenceProperties");
  turbulenceProperties_dict_file << turbulenceProperties_dict;
}

void Project::UpdateControlDict_i()
{
  std::string control_dict = R"(
/*--------------------------------*- C++ -*----------------------------------*\
| =========                 |                                                |
| \\      /  F ield         | cfMesh: A library for mesh generation          | 
|  \\    /   O peration     |                                                |
|   \\  /    A nd           | Author: Franjo Juretic                         | 
|    \\/     M anipulation  | E-mail: franjo.juretic@c-fields.com            |
\*---------------------------------------------------------------------------*/

    FoamFile
  {
    version 2.0;
    format ascii;
    class dictionary;
    location "system";
    object meshDict;
  }

  // ************************************************************************* //

  applicationClass;

  startFrom latestTime;

  startTime 0;

  stopAt endTime;

  endTime 500;

  deltaT 1;

  writeControl timeStep;

  writeInterval 100;

  cycleWrite 0;

  writeFormat ascii;

  writeCompression uncompressed;

  timeFormat general;

  timePrecision 6;

  runTimeModifiable yes;

  nCorrectors 2;

  nNonOrthogonalCorrectors 0;


  // ************************************************************************* //
)";

  std::ofstream control_dict_file(this->m_SystemSubSpace + "/controlDict");
  control_dict_file << control_dict;
}
void Project::UpdateFvSchemes_i()
{
  std::string fvSchemes_dict = R"(
    /*--------------------------------*- C++ -*----------------------------------*\
| =========                 |                                                 |
| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
|  \\    /   O peration     | Version:  v1806                                 |
|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
|    \\/     M anipulation  |                                                 |
\*---------------------------------------------------------------------------*/
FoamFile
{
    version     2.0;
    format      ascii;
    class       dictionary;
    object      fvSchemes;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

ddtSchemes
{
    default         steadyState;
}

gradSchemes
{
    default         Gauss linear;
    limitedGrad     faceLimited leastSquares 1.0;
    //grad(U)         cellMDLimited Gauss linear 1;
}

//   div(phi,U)      bounded Gauss limitedLinearV 1.0; //linearUpwindV limitedGrad;
//   div(phi,K)      bounded Gauss linearUpwind limitedGrad;


divSchemes
{
    default         none;
    div(phi,U)      bounded Gauss limitedLinearV 1.0;
    div(phi,k)      bounded Gauss limitedLinear 1.0;
    div(phi,omega)  bounded Gauss linearUpwind limitedGrad;//bounded Gauss limitedLinear 1.0;
    div((nuEff*dev2(T(grad(U))))) Gauss linear;
}

laplacianSchemes
{
    default         Gauss linear limited 0.5; //corrected;
}

interpolationSchemes
{
    default         linear;
}

snGradSchemes
{
    default         limited 0.5;//corrected;
}

wallDist
{
    method meshWave;
    corrected yes;
}


// ************************************************************************* //
)";

  std::ofstream fvSchemes_dict_file(this->m_SystemSubSpace + "/fvSchemes");
  fvSchemes_dict_file << fvSchemes_dict;
}
void Project::UpdateFvSolution_i()
{
  std::string fvSolution_dict = R"(
/*--------------------------------*- C++ -*----------------------------------*\
| =========                 |                                                 |
| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
|  \\    /   O peration     | Version:  v1806                                 |
|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
|    \\/     M anipulation  |                                                 |
\*---------------------------------------------------------------------------*/
FoamFile
{
    version     2.0;
    format      ascii;
    class       dictionary;
    object      fvSolution;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

solvers
{
    p
    {
        solver          GAMG;
        smoother        GaussSeidel;
        tolerance       1e-7;
        relTol          0.001;
	maxIter		200;
    }

    Phi
    {
        $p;
    }

    U
    {
        solver          smoothSolver;
        smoother        GaussSeidel;
        tolerance       1e-8;
        relTol          0;
        nSweeps         1;
    }

    k
    {
        solver          smoothSolver;
        smoother        GaussSeidel;
        tolerance       1e-8;
        relTol          0.00001;
        nSweeps         1;
    }

    omega
    {
        solver          smoothSolver;
        smoother        GaussSeidel;
        tolerance       1e-8;
        relTol          0.00001;
        nSweeps         1;
    }
}

SIMPLE
{
    nNonOrthogonalCorrectors 1;
    consistent 	yes;
    pMax	1e4;
    pMin	-1e4;
}

potentialFlow
{
    nNonOrthogonalCorrectors 10;
}

relaxationFactors
{
    equations
    {
        U               0.7;
        k               0.5;
        omega           0.5;
	p		0.3;
    }
}

cache
{
    grad(U);
}

// ************************************************************************* //

)";

  std::ofstream fvSolution_dict_file(this->m_SystemSubSpace + "/fvSolution");
  fvSolution_dict_file << fvSolution_dict;
}
void Project::UpdateDecomposeParDict()
{
  std::string decomposeParDict_dict = R"(
/*--------------------------------*- C++ -*----------------------------------*\
| =========                 |                                                 |
| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
|  \\    /   O peration     | Version:  5                                     |
|   \\  /    A nd           | Web:      www.OpenFOAM.org                      |
|    \\/     M anipulation  |                                                 |
\*---------------------------------------------------------------------------*/
FoamFile
{
    version     2.0;
    format      ascii;
    class       dictionary;
    object      decomposeParDict;
}

numberOfSubdomains  8;
method              scotch;
)";

  std::ofstream decomposeParDict_dict_file(this->m_SystemSubSpace + "/decomposeParDict");
  decomposeParDict_dict_file << decomposeParDict_dict;
}

void Project::UpdateMeshDict_i(const conduit_cpp::Node& node)
{
  LOG(ERROR) << "UpdateMeshDict_i";

  std::string mesh_dict = MeshDictFormater::FormatMeshDict(node);
 
  std::ofstream mesh_dict_file(this->m_SystemSubSpace + "/meshDict");
  mesh_dict_file << mesh_dict;
  
}

void Project::SetBlueCFDEnv(const std::string& blueCFDPath)
{
  std::string home = blueCFDPath;
  _putenv(fmt::format("HOME={}", home).c_str());

  _putenv(fmt::format("AddOns_ParaView_DIR={}\\AddOns\\ParaView", home).c_str());
  _putenv(fmt::format("BLUECFDPATH={}", home).c_str());
  _putenv("USER=ofuser");
  _putenv("USERNAME=ofuser");
  _putenv("WM_PROJECT=OpenFOAM");
  _putenv("WM_PROJECT_VERSION=5.x");
  _putenv(fmt::format("FOAM_INST_DIR={}", home).c_str());
  _putenv(fmt::format("WM_PROJECT_INST_DIR={}", getenv("FOAM_INST_DIR")).c_str());
  _putenv(fmt::format("WM_PROJECT_DIR={}\\{}-{}",
                     getenv("FOAM_INST_DIR"),
                     getenv("WM_PROJECT"),
                     getenv("WM_PROJECT_VERSION"))
           .c_str());
  _putenv(fmt::format("WM_PROJECT_USER_DIR={}\\{}-of5", getenv("HOME"), getenv("USER")).c_str());
  _putenv(fmt::format("WM_THIRD_PARTY_DIR={}\\ThirdParty-{}-of5",
                     getenv("WM_PROJECT_INST_DIR"),
                     getenv("WM_PROJECT_VERSION"))
           .c_str());

  _putenv("WM_ARCH=mingw_w64");
  _putenv("WM_ARCH_OPTION=64");
  _putenv("WM_CC=x86_64-w64-mingw32-gcc");
  _putenv("WM_COMPILER=Gcc");
  _putenv("WM_COMPILER_ARCH=x86_64-w64-mingw32");
  _putenv("WM_COMPILER_TYPE=system");
  _putenv("WM_COMPILE_OPTION=Opt");
  _putenv("WM_CXX=x86_64-w64-mingw32-g++");
  _putenv(fmt::format("WM_DIR=={}\\wmake", getenv("WM_PROJECT_DIR")).c_str());
  _putenv("WM_LABEL_OPTION=Int32");
  _putenv("WM_LABEL_SIZE=32");
  _putenv("WM_LINK_LANGUAGE=c++");
  _putenv("WM_MPLIB=MSMPI71");
  _putenv("WM_OSTYPE=MSwindows");
  _putenv("WM_PRECISION_OPTION=DP");
  _putenv("WM_TARGET_ARCH=mingw_w64");
  _putenv(fmt::format("WM_OPTIONS={}{}{}{}{}",
                     getenv("WM_ARCH"),
                     getenv("WM_COMPILER"),
                     getenv("WM_PRECISION_OPTION"),
                     getenv("WM_LABEL_OPTION"),
                     getenv("WM_COMPILE_OPTION"))
           .c_str());

  _putenv(fmt::format("ParaView_DIR={}\\AddOns\\ParaView", getenv("HOME")).c_str());
  _putenv("ParaView_MAJOR=5.4");
  _putenv("ParaView_VERSION=5.4.1");

  _putenv(fmt::format("BOOST_ARCH_PATH={}\\msys64\\mingw64", getenv("HOME")).c_str());
  _putenv(fmt::format("CGAL_ARCH_PATH={}\\msys64\\mingw64", getenv("HOME")).c_str());

  _putenv("MPI_ACCESSORY_OPTIONS=-genvlist WM_PROJECT_DIR,MPI_BUFFER_SIZE,PATH");
  _putenv(fmt::format("{}\\ThirdParty-{}\\platforms\\{}{}\\MS-MPI-7.1",
                     getenv("HOME"),
                     getenv("WM_PROJECT_VERSION"),
                     getenv("WM_ARCH"),
                     getenv("WM_COMPILER"))
           .c_str());
  _putenv("MPI_BUFFER_SIZE=20000000");

  _putenv("FOAMY_HEX_MESH=1");
  _putenv(fmt::format("FOAM_APP={}\\applications", getenv("WM_PROJECT_DIR")).c_str());
  _putenv(fmt::format(
           "FOAM_APPBIN={}\\platforms\\{}\\bin", getenv("WM_PROJECT_DIR"), getenv("WM_OPTIONS"))
           .c_str());
  _putenv(fmt::format("FOAM_ETC={}\\etc", getenv("WM_PROJECT_DIR")).c_str());
  _putenv(fmt::format("FOAM_EXT_LIBBIN={}\\ThirdParty-{}\\platforms\\{}{}{}{}\\lib",
                     getenv("HOME"),
                     getenv("WM_PROJECT_VERSION"),
                     getenv("WM_ARCH"),
                     getenv("WM_COMPILER"),
                     getenv("WM_COMPILE_OPTION"),
                     getenv("WM_LABEL_OPTION"))
           .c_str());
  _putenv(fmt::format("FOAM_JOB_DIR={}\\jobControl", getenv("HOME")).c_str());
  _putenv(fmt::format(
           "FOAM_LIBBIN={}\\platforms\\{}\\lib", getenv("WM_PROJECT_DIR"), getenv("WM_OPTIONS"))
           .c_str());
  _putenv("FOAM_MPI=MS-MPI-7.1");
  _putenv(fmt::format("FOAM_RUN={}\\run", getenv("WM_PROJECT_USER_DIR")).c_str());
  _putenv("FOAM_SIGFPE=1");
  _putenv(fmt::format("FOAM_SITE_APPBIN={}\\site\\{}\\platforms\\{}\\bin",
                     getenv("HOME"),
                     getenv("WM_PROJECT_VERSION"),
                     getenv("WM_OPTIONS"))
           .c_str());
  _putenv(fmt::format("FOAM_SITE_LIBBIN={}\\site\\{}\\platforms\\{}\\lib",
                     getenv("HOME"),
                     getenv("WM_PROJECT_VERSION"),
                     getenv("WM_OPTIONS"))
           .c_str());
  _putenv(fmt::format("FOAM_SOLVERS={}\\applications\\solvers", getenv("WM_PROJECT_DIR")).c_str());
  _putenv(fmt::format("FOAM_SRC={}\\src", getenv("WM_PROJECT_DIR")).c_str());
  _putenv(fmt::format("FOAM_TUTORIALS={}\\tutorials", getenv("WM_PROJECT_DIR")).c_str());
  _putenv(fmt::format("FOAM_USER_APPBIN={}\\platforms\\{}\\bin",
                     getenv("WM_PROJECT_USER_DIR"),
                     getenv("WM_OPTIONS"))
           .c_str());
  _putenv(fmt::format("FOAM_USER_LIBBIN={}\\platforms\\{}\\lib",
                     getenv("WM_PROJECT_USER_DIR"),
                     getenv("WM_OPTIONS"))
           .c_str());
  _putenv(
    fmt::format("FOAM_UTILITIES={}\\applications\\utilities", getenv("WM_PROJECT_DIR")).c_str());

  _putenv(
    fmt::format(
      "PATH={}\\ThirdParty-{}\\platforms\\{}{}\\{}\\bin;{}\\platforms\\{}\\bin;{}\\site\\{}"
      "\\platforms\\{}\\bin;{}\\platforms\\{}\\bin;{}\\bin;{}\\wmake;{}\\msys64\\mingw64\\bin;{};{}"
      "\\SYSTEM32;{}\\AddOns\\gnuplot\\bin;{}\\AddOns\\notepad2;{}\\platforms\\{}\\lib;{}"
      "\\platforms\\{}\\lib\\{};{}\\ThirdParty-{}\\platforms\\{}{}{}{}\\lib\\{};{}\\ThirdParty-{}"
      "\\platforms\\{}{}\\{}\\lib;{}\\site\\{}\\platforms\\{}\\lib;{}\\platforms\\{}\\lib;{}"
      "\\ThirdParty-{}\\platforms\\{}{}{}{}\\lib;{}\\platforms\\{}\\lib\\dummy",
      getenv("HOME"),
      getenv("WM_PROJECT_VERSION"),
      getenv("WM_ARCH"),
      getenv("WM_COMPILER"),
      getenv("FOAM_MPI"),
      getenv("WM_PROJECT_USER_DIR"),
      getenv("WM_OPTIONS"),
      getenv("HOME"),
      getenv("WM_PROJECT_VERSION"),
      getenv("WM_OPTIONS"),
      getenv("WM_PROJECT_DIR"),
      getenv("WM_OPTIONS"),
      getenv("WM_PROJECT_DIR"),
      getenv("WM_PROJECT_DIR"),
      getenv("HOME"),
      getenv("WINDIR"),
      getenv("WINDIR"),
      getenv("HOME"),
      getenv("HOME"),
      getenv("WM_PROJECT_USER_DIR"),
      getenv("WM_OPTIONS"),
      getenv("WM_PROJECT_DIR"),
      getenv("WM_OPTIONS"),
      getenv("FOAM_MPI"),
      getenv("HOME"),
      getenv("WM_PROJECT_VERSION"),
      getenv("WM_ARCH"),
      getenv("WM_COMPILER"),
      getenv("WM_PRECISION_OPTION"),
      getenv("WM_LABEL_OPTION"),
      getenv("FOAM_MPI"),
      getenv("HOME"),
      getenv("WM_PROJECT_VERSION"),
      getenv("WM_ARCH"),
      getenv("WM_COMPILER"),
      getenv("FOAM_MPI"),
      getenv("HOME"),
      getenv("WM_PROJECT_VERSION"),
      getenv("WM_OPTIONS"),
      getenv("WM_PROJECT_DIR"),
      getenv("WM_OPTIONS"),
      getenv("HOME"),
      getenv("WM_PROJECT_VERSION"),
      getenv("WM_ARCH"),
      getenv("WM_COMPILER"),
      getenv("WM_PRECISION_OPTION"),
      getenv("WM_LABEL_OPTION"),
      getenv("WM_PROJECT_DIR"),
      getenv("WM_OPTIONS"))
      .c_str());
}

void Project::InitWorkSpace(const conduit_cpp::Node& node)
{
  // init 0
  UpdateaIncludeInitialConditions_i();
  UpdateaIncludeFixedInlet_i();
  UpdateaIncludefrontBackUpperPatches_i();

  UpdateaPressure_i();
  UpdateaVelocity_i();
  UpdateaOmega_i();
  UpdateaKinetic_i();
  UpdateaEpsilon_i();
  UpdateaNut_i();

  //init constant
  UpdateaTransportProperties_i();
  UpdateaTurbulenceProperties_i();

  // init system
  UpdateControlDict_i();
  UpdateFvSchemes_i();
  UpdateFvSolution_i();
  UpdateDecomposeParDict();
  UpdateMeshDict_i(node);
}

void Project::AddMesh(std::shared_ptr<Mesh> mesh)
{
  m_Mesh = mesh;
}

void Project::GenerateBoundBoxing(const conduit_cpp::Node& node)
{
  auto command =
    R"( {_xNLength} {_xPLength} {_yNLength} {_yPLength} {_zNLength} {_zPLength})";
  fmt::dynamic_format_arg_store<fmt::format_context> args;
  args.push_back(fmt::arg("_xNLength", node[name_boundingBox_xNLength].to_double()));
  args.push_back(fmt::arg("_xPLength", node[name_boundingBox_xPLength].to_double()));
  args.push_back(fmt::arg("_yNLength", node[name_boundingBox_yNLength].to_double()));
  args.push_back(fmt::arg("_yPLength", node[name_boundingBox_yPLength].to_double()));
  args.push_back(fmt::arg("_zNLength", node[name_boundingBox_zNLength].to_double()));
  args.push_back(fmt::arg("_zPLength", node[name_boundingBox_zPLength].to_double()));
  m_boundBoxPara = fmt::vformat(command, args);
}

bool Project::BuildMesh()
{
  m_Mesh->SetWorkSpace(m_WorkSpace);
  m_Mesh->SetBoundBoxingPar(m_boundBoxPara);
  m_Mesh->Build();
  return true;
}

void Project::AddGeometry(std::shared_ptr<Geometry> geometry)
{
  m_Geometry = geometry;

  //copy geometry to target
  CopyGeometryToTarget_i();
}
